/*
 *  Copyright (C) 2011 Sherlock Downloader
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.sherlock.downloader;

import java.net.URL;
import java.text.DecimalFormat;
import java.util.Observable;

import org.sherlock.commons.download.FetcherProxy;

/**
 *
 * @author Sherlock Downloader
 */
public class Download extends Observable implements Comparable {

    public enum Status {

        DOWNLOADING, PAUSED, COMPLETE, CANCELLED, ERROR, READY
    }
    private FetcherProxy fetcher;
    private Status status;
    private String fileName;
    private URL localURL;
    private URL remoteURL;
    private int downloaded;
    private int priority;
    private int size;

    /**
     * Constructs a new download with the specified URLS.
     * 
     * @param localURL URL where to save the file.
     * @param remoteURL URL of the file.
     */
    public Download(URL localURL, URL remoteURL) {
    	this(localURL, remoteURL, Status.PAUSED, 0, 0);
    }

    /**
     * Constructs a new download with the specified URLS.
     * @param localURL URL where to save the file.
     * @param remoteURL URL of the file.
     * @param status Status of the download.
     * @param size Size of the file.
     * @param downloaded Amount of bytes already downloaded.
     */
    public Download(URL localURL, URL remoteURL, Status status, int size, int downloaded) {
        this.localURL = localURL;
        this.remoteURL = remoteURL;
        this.status = status;
        this.size = size;
        this.downloaded = downloaded;
        
        fileName = localURL.toString();
    	fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
    }

    /**
     * Returns the amount of download bytes.
     * 
     * @return amount of downloaded bytes.
     */
    public int getDownloaded() {
        return downloaded;
    }
    
    public String getHumanDownloaded(){
    	return getAppropriateUnit(downloaded);
    }

    public FetcherProxy getFetcher() {
        return fetcher;
    }

    /**
     * Returns the name of the file.
     * 
     * @return name of the file.
     */
    public String getFileName() {
    	return fileName;
    }

    /**
     * Returns the URL of the file on the local computer.
     * 
     * @return URL of the local file.
     */
    public URL getLocalURL() {
        return localURL;
    }

    /**
     * Returns the progress of the download measured by percentage
     * of bytes downloaded.
     * 
     * @return progress of the download.
     */
    public double getProgress() {
        return downloaded / (double) size * 100;
    }
    
    public int getPriority() {
    	return priority;
    }
    
    public String getHumanProgress(){
    	return (int) getProgress() + "%";
    }

    /**
     * Returns the URL of the file on the remote server.
     * 
     * @return URL of the remote file.
     */
    public URL getRemoteURL() {
        return remoteURL;
    }

    /**
     * Returns the size of the file.
     * 
     * @return size of the file.
     */
    public int getSize() {
        return size;
    }
    
    public String getHumanSize(){
    	return getAppropriateUnit(size);
    }

    /**
     * Returns the status of the download.
     * @return The status of the download.
     */
    public Status getStatus() {
        return status;
    }

    /**
     * Sets the amount of bytes already downloaded and notifies observers.
     * @param downloaded Amount of bytes downloaded.
     */
    public void setDownloaded(int downloaded) {
        this.downloaded = downloaded;

        setChanged();
        notifyObservers();
    }

    public void setFetcher(FetcherProxy fetcher) {
        this.fetcher = fetcher;
    }

    public void setPriority(int priority) {
    	this.priority = priority;
    }
    
    /**
     * Sets the size of the file.
     * @param size The size (in bytes) of the file.
     */
    public void setSize(int size) {
        this.size = size;
    }

    /**
     * Change the status of the download.
     * 
     * @param status new Status.
     */
    public void setStatus(Status status) {
        this.status = status;

        setChanged();
        notifyObservers();
    }

    /**
     * Gets the appropriate unit for an specific amount of bytes. 
     * @param amount Bytes to be converted.
     * @return  Bytes in an appropriate unit.
     */
    private String getAppropriateUnit(int amount) {
        DecimalFormat df = new DecimalFormat(".##");
        if (amount < 1024) {
            return amount + " bytes";
        }
        if (amount < 1048576) {
            return df.format((double) amount / 1024) + " KB";
        }
        if (amount < 1073741824) {
            return df.format((double) amount / 1024 / 1024) + " MB";
        }
        return df.format((double) amount / 1024 / 1024 / 1024) + " GB";
    }

    @Override
    public String toString() {
        return getAppropriateUnit(downloaded) + " / " + getAppropriateUnit(size) + " (" + (int) getProgress() + "%)";
    }

	@Override
	public int compareTo(Object arg0) {
		// TODO Auto-generated method stub
		return 0;
	}
}